/* ============================================================ */
/* File: LDSCRIPT.C						*/
/*								*/
/* Copyright (C) 2001, Daniel W. Lewis and Prentice-Hall	*/
/*								*/
/* Purpose: Creates linker script file for use with ld.		*/
/*								*/
/* Modification History:					*/
/*								*/
/* ============================================================ */

#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>

/*
 * Usage: ldscript >linker.cmd	
 *        ldscript p >linker.cmd  (to also use libepong.a)
 */

char *title[] =
{
"/* ------------------------------------------------------------ */",
"/* Script file for linker ld.  Designed for use on an IBM-PC.   */",
"/* ------------------------------------------------------------ */",
NULL
} ;

char *script[] =
{
"OUTPUT_FORMAT(\"binary\")",
"OUTPUT(\"embedded.bin\")",
"EXTERN(start)",
"ENTRY(start)",
"MEMORY {",
"   /* --------------------------------------------------------- */",
"   /* The loader starts execution of the application at         */",
"   /* physical address zero, so .start must be placed in        */",
"   /* conventional memory, thus '>conventional'. You may put    */",
"   /* one or more of the remaining sections in extended memory  */",
"   /* by replacing their respective '>conventional' directives  */",
"   /* with a '>extended' directive where it appears below. If   */",
"   /* you do, however, the application will not run on a        */",
"   /* machine with no extended memory.                          */",
"   /* --------------------------------------------------------- */",
"   conventional : ORIGIN = 0x00000000, LENGTH = 640*1024",
"       reserved : ORIGIN = 0x000A0000, LENGTH = 384*1024",
"       extended : ORIGIN = 0x00100000, LENGTH = 4095*1024*1024",
"}",
"",
"SECTIONS {",
"   .text 0x00000000 : {",
"       text_frst = . ;",
"       *(.start)",
"       *(.init)",
"       *(.text)",
"       text_last = . - 1 ;",
"   } >conventional",
"",
"   .data : {",
"       data_frst = . ;",
"       *(.data)",
"       data_last = . - 1 ;",
"   } >conventional",
"",
"   .bss : {",
"       bss_frst = . ;",
"       *(.bss)",
"       *(COMMON)",
"       bss_last = . - 1 ;",
"   } >conventional",
"",
"   /* --------------------------------------------------------- */",
"   /* The stack sits just above the bss.  It's size is set here */",
"   /* so that it can be changed without recompiling the code.   */",
"   /* --------------------------------------------------------- */",
"   stack_frst = bss_last + 1 ;",
"   stack_last = bss_last + 32768 ;",
"",
"   /* --------------------------------------------------------- */",
"   /* The heap starts just above the stack and gets the rest.   */",
"   /* --------------------------------------------------------- */",
"   heap_frst = stack_last + 1 ;",
"}",
NULL
} ;

void Error(char *msg, ...)
	{
	va_list arg ;

	va_start(arg, msg) ;
	fprintf(stderr, "\nError: ") ;
	vfprintf(stderr, msg, arg) ;
	fprintf(stderr, "\n") ;
	va_end(arg) ;
	exit(255) ;
	}

void Output(char **text)
	{
	while (*text != NULL) printf("%s\n", *text++) ;
	}

void Library(char *name, char *spec, int size)
	{
	char cmd[500] ;
	FILE *fp ;

	sprintf(cmd, "gcc -print-file-name=%s.a", name) ;
	fp = popen(cmd, "r") ;
	if (!fp) Error("Can't popen: %s", cmd) ;
	fgets(spec, size, fp) ;
	*strchr(spec, '\n') = '\0' ;
	pclose(fp) ;
	}

int main(int argc, char *argv[])
	{
	char filespec[500] ;

	Output(title) ;
	if (argc == 2 && argv[1][0] == 'p')
	  printf("INPUT(\"./libepong.a\")\n") ;
	printf("INPUT(\"./libepc.a\")\n") ;
	Library("libc", filespec, sizeof(filespec)) ;
	printf("INPUT(\"%s\")\n", filespec) ;
	Library("libgcc", filespec, sizeof(filespec)) ;
	printf("INPUT(\"%s\")\n", filespec) ;
	Output(script) ;

	return 0 ;
	}
